package Client

import (
	"encoding/json"
	"errors"
	"fmt"
	"gateway/websocket/logic"
	"gateway/websocket/types"
	"github.com/gorilla/websocket"
	"log"
	"sync"
	"time"
)

// Client 客户端连接信息
type Client struct {
	ID            string          // 连接ID
	AccountId     string          // 账号id, 一个账号可能有多个连接
	Socket        *websocket.Conn // 连接
	HeartbeatTime int64           // 前一次心跳时间
}

// 读取信息，即收到消息
func (c *Client) Read() {
	defer func() {
		_ = c.Socket.Close()
	}()
	for {
		// 读取消息
		_, body, err := c.Socket.ReadMessage()
		if err != nil {
			break
		}

		msg := types.RequestMessage{}
		err = json.Unmarshal(body, &msg)
		if err != nil {
			s := make([]string, 0)
			s = append(s, c.AccountId)
			ms := types.GetServiceMessage(types.SysErr, err.Error())

			err = Send(s, ms)
			fmt.Println(err)
			continue
		}

		if msg.Type == types.MessageTypeHeartbeat { // 维持心跳消息
			// 刷新连接时间
			c.HeartbeatTime = time.Now().Unix()

			// 回复心跳
			replyMsg := CreateReplyMsg(types.ServiceMessage{
				Type: types.MessageTypeHeartbeat,
				Data: "回复心跳",
			})
			err = c.Socket.WriteMessage(websocket.TextMessage, replyMsg)
			if err != nil {
				log.Println(err)
			}
			continue
		} else {
			s := make([]string, 0)
			s = append(s, c.AccountId)
			typeLogic, err := GetTypeLogic(msg)

			if err != nil {
				fmt.Println(msg)
				borerErr := types.GetServiceMessage(types.SysErr, err.Error())
				err = Send(s, borerErr)
				continue
			}
			err = Send(s, typeLogic)
			continue
		}
	}
}

// ClientManager 客户端管理
type ClientManager struct {
	Clients  map[string]*Client  // 保存连接
	Accounts map[string][]string // 账号和连接关系,map的key是账号id即：AccountId，这里主要考虑到一个账号多个连接
	Mu       *sync.Mutex
}

// Manager 定义一个管理Manager
var Manager = ClientManager{
	Clients:  make(map[string]*Client),  // 参与连接的用户，出于性能的考虑，需要设置最大连接数
	Accounts: make(map[string][]string), // 账号和连接关系
	Mu:       new(sync.Mutex),
}

var (
	RegisterChan   = make(chan *Client, types.ChanBufferRegister)   // 注册
	UnregisterChan = make(chan *Client, types.ChanBufferUnregister) // 注销
)

func CreateReplyMsg(content types.ServiceMessage) []byte {
	fmt.Println("获取到了信息")
	msg, _ := json.Marshal(content)
	return msg
}

// Register 注册注销
func Register() {
	for {
		select {
		case conn := <-RegisterChan: // 新注册，新连接
			// 加入连接,进行管理
			AccountBind(conn)

			// 回复消息
			content := CreateReplyMsg(types.ServiceMessage{
				Type: types.MessageTypeRegister,
				Data: "回复注册/注销",
			})
			_ = conn.Socket.WriteMessage(websocket.TextMessage, content)

		case conn := <-UnregisterChan: // 注销，或者没有心跳
			// 关闭连接
			_ = conn.Socket.Close()

			// 删除Client
			UnAccountBind(conn)
		}
	}
}

// AccountBind 绑定账号
func AccountBind(c *Client) {
	Manager.Mu.Lock()
	defer Manager.Mu.Unlock()

	// 加入到连接
	Manager.Clients[c.ID] = c

	// 加入到绑定
	if _, ok := Manager.Accounts[c.AccountId]; ok { // 该账号已经有绑定，就追加一个绑定
		Manager.Accounts[c.AccountId] = append(Manager.Accounts[c.AccountId], c.ID)
	} else { // 没有就新增一个账号的绑定切片
		Manager.Accounts[c.AccountId] = []string{c.ID}
	}
}

// UnAccountBind  解绑账号
func UnAccountBind(c *Client) {
	Manager.Mu.Lock()
	defer Manager.Mu.Unlock()

	// 取消连接
	delete(Manager.Clients, c.ID)

	// 取消绑定
	if len(Manager.Accounts[c.AccountId]) > 0 {
		for k, clientId := range Manager.Accounts[c.AccountId] {
			if clientId == c.ID { // 找到绑定客户端Id
				Manager.Accounts[c.AccountId] = append(Manager.Accounts[c.AccountId][:k], Manager.Accounts[c.AccountId][k+1:]...)
			}
		}
	}
}

// Heartbeat 维持心跳
func Heartbeat() {
	for {
		// 获取所有的Clients
		Manager.Mu.Lock()
		clients := make([]*Client, len(Manager.Clients))
		for _, c := range Manager.Clients {
			clients = append(clients, c)
		}
		Manager.Mu.Unlock()

		for _, c := range clients {
			if time.Now().Unix()-c.HeartbeatTime > types.HeartbeatTime {
				UnAccountBind(c)
			}
		}

		time.Sleep(time.Second * types.HeartbeatCheckTime)
	}
}

// Start 管理连接
func Start() {
	// 检查心跳
	go func() {
		defer func() {
			if r := recover(); r != nil {
				log.Println(r)
			}
		}()
		Heartbeat()
	}()

	// 注册注销
	go func() {
		defer func() {
			if r := recover(); r != nil {
				log.Println(r)
			}
		}()
		Heartbeat()
	}()
}

// GetClient 根据账号获取连接
func GetClient(accountId string) []*Client {
	clients := make([]*Client, 0)

	Manager.Mu.Lock()
	defer Manager.Mu.Unlock()

	if len(Manager.Accounts[accountId]) > 0 {
		for _, clientId := range Manager.Accounts[accountId] {
			if c, ok := Manager.Clients[clientId]; ok {
				clients = append(clients, c)
			}
		}
	}

	return clients
}

// Send 发送消息
func Send(accounts []string, message types.ServiceMessage) error {
	msg, err := json.Marshal(message)
	if err != nil {
		return err
	}

	for _, accountId := range accounts {
		// 获取连接id
		clients := GetClient(accountId)
		// 发送消息
		for _, c := range clients {
			_ = c.Socket.WriteMessage(websocket.TextMessage, msg)
		}
	}

	return nil
}
func GetTypeLogic(req types.RequestMessage) (types.ServiceMessage, error) {
	var (
		d = types.ServiceMessage{}
	)

	if req.Data == "" {
		return d, errors.New("请传入参数")
	}

	d.Type = req.Type
	switch req.Type {
	case types.SysHi:
		data, err := types.GetMessageData[types.GetReqData](req.Data)
		if err != nil {
			return d, err
		}
		err = logic.TestBackDAta(data, &d)
		if err != nil {
			return d, err
		}
		return d, nil
	case types.SysGetFileList:
		data, err := types.GetMessageData[types.SysFileRequest](req.Data)
		if err != nil {
			return d, err
		}
		err = logic.GetFileList(data, &d)
		if err != nil {
			return d, err
		}
		return d, nil
	default:
		d.Type = types.SysErr
		return d, errors.New("请传入正确的指令")
	}

}
